Data filtering

Patient Enrollment Filtering: Claims data were filtered to include only patients with enrollment periods exceeding 12 months. This criterion was set to ensure that the data represented a sufficiently long period to analyze treatment patterns and outcomes accurately.

Linking rx_information: The rx_information data was linked to the claims data using National Drug Codes (NDCs). This linkage was essential for integrating prescription information with the claims data.

Identifying Buprenorphine OUD Cohort: The buprenorphine opioid use disorder (OUD) cohort was identified using the Universal Service Code (usc_cd) of 78430, which corresponds to ‘Drug Dependence’.

Chunk Processing Function: A custom function was written to process each chunk of data separately. This approach ensured that the dataset was handled efficiently and effectively, especially given the potentially large size of the claims data. The processed chunks were then combined into a single dataset.

Duplicate Removal: Duplicate entries were meticulously removed to prevent redundancy and ensure the accuracy of the dataset.

Joining with Demographics: The resulting data frame was joined with demographic information to create the final dataset, named ‘claims_demo’. This final dataset integrated all necessary data elements, including claims, prescriptions, and patient demographics, providing a comprehensive foundation for subsequent analyses.

The final cohort now has 3358850 claims total and 187790 individual patients.

Data linkage

Linking Demographic Data with Claims: The demographic data was linked to the claims data via patient IDs. This step ensured that each claim could be associated with the corresponding patient’s demographic information.

Linking RX Information with Claims: The rx_information data was linked to the claims data using the NDCs. This linkage was essential for associating specific medications with patient claims.

‘claims_demo’ is the final dataset.

library(dplyr)
library(data.table)
library(ggplot2) 
library(plotly)
library(usmap)
library(gridExtra)

Attaching package: ‘gridExtra’

The following object is masked from ‘package:randomForest’:

    combine

The following object is masked from ‘package:dplyr’:

    combine
filter_cohort<-function(df) {
class(df$ndc) <- "character"
class(rx_information$ndc) <- "character"
claims_rx <- df %>% 
  left_join(.,rx_information, by = "ndc")
keywords <- c("BUNAVAIL", "BUPRENORPHINE/NALOX", "BUPRENORPHINE HCL", "BUPRENORPHINE HCL/NALOXON", "BUPRENORPHINE HYDROCHLORI", "PROBUPHINE IMPLANT KIT", "SUBLOCADE", "SUBOXONE", "SUBUTEX", "ZUBSOLV") 
pattern<-paste(keywords,collapse="|")
claims_rxb <-claims_rx %>% 
  filter(grepl(pattern, product_name, ignore.case=TRUE) | grepl(pattern, generic_name, ignore.case=TRUE))
claims_rxb_12months <- claims_rxb %>% 
  filter(.$pat_id %in% patients_full_enroll)
duplicates<-apply(claims_rxb_12months,1,function(row) length(unique(row)==1))
claims_rxb_12months<-claims_rxb_12months[!duplicates, ]
claims_rxb_12mo<-claims_rxb_12months[claims_rxb_12months$usc_cd == "78340", ]
fwrite(claims_rxb_12mo, "df2_filtered")
claims_rxb_12mo2<-claims_rxb_12mo %>% select(pat_id, dayssup, quan, from_dt, to_dt, ndc, proc_cde, diagprc_ind, diag1, diag2, diag3, diag4, diag5, diag6, diag7, diag8) %>% arrange(pat_id)
fwrite(claims_rxb_12mo2, "df2_filtered_selected") 
return(head(claims_rxb_12mo2)) 
} 
filter_cohort(d2)

missingness check

missingness <- colSums(is.na(claims_demo[,c(1:20)])) / nrow(claims_demo[,c(1:20)]) * 100

missingness_df <- data.frame(
  Column = names(missingness),
  MissingPercentage = missingness
) %>%
  arrange(desc(MissingPercentage))

p <- plot_ly(
  data = missingness_df,
  x = ~MissingPercentage,
  y = ~reorder(Column, MissingPercentage),
  type = 'bar',
  orientation = 'h',
  text = ~paste("Missing: ", round(MissingPercentage, 2), "%"),
  hoverinfo = 'text',
  marker = list(color = 'steelblue')
) %>%
  layout(
    title = 'Percentage of Missing Values by Column',
    xaxis = list(title = 'Missing Percentage (%)'),
    yaxis = list(title = 'Column', automargin = TRUE, tickfont = list(size = 10)),
    margin = list(l = 200, r = 50, t = 50, b = 50)  # Adjust margins to fit labels
  )

p
missingness <- colSums(is.na(claims_demo[,-c(1:20)])) / nrow(claims_demo[,-c(1:20)]) * 100

missingness_df <- data.frame(
  Column = names(missingness),
  MissingPercentage = missingness
) %>%
  arrange(desc(MissingPercentage))

p <- plot_ly(
  data = missingness_df,
  x = ~MissingPercentage,
  y = ~reorder(Column, MissingPercentage),
  type = 'bar',
  orientation = 'h',
  text = ~paste("Missing: ", round(MissingPercentage, 2), "%"),
  hoverinfo = 'text',
  marker = list(color = 'steelblue')
) %>%
  layout(
    title = 'Percentage of Missing Values by Column',
    xaxis = list(title = 'Missing Percentage (%)'),
    yaxis = list(title = 'Column', automargin = TRUE, tickfont = list(size = 10)),
    margin = list(l = 200, r = 50, t = 50, b = 50)  # Adjust margins to fit labels
  )

p

Since diag9-diag12 are missing 100%, we could remove those columns

claims_demo<- claims_demo %>%
  select(-diag9, -diag10, -diag11, -diag12)

Since diag9-diag12 are missing 100%, we could remove those columns

Group by patient ID and dates claimed

claims_demo <- claims_demo %>% arrange(pat_id, from_dt) %>% group_by(pat_id) 
claims_demo <- claims_demo %>%
  mutate(year = year(ymd(from_dt)))

The final cohort ready for identifying episodes

head(claims_demo,100)

Summaries of Days prescribed and quantity prescribed

table(claims_demo$dayssup)

    -90     -60     -35     -33     -32     -30     -29     -28 
      2       4       1       1       1     247       2      24 
    -27     -26     -25     -24     -23     -22     -21     -20 
      1       3       1       1       1       2       6      10 
    -18     -16     -15     -14     -12     -11     -10      -9 
      2       5      26      30       1       1      21       6 
     -8      -7      -6      -5      -4      -3      -2      -1 
     16      26      19     129      18      17      33      28 
      0       1       2       3       4       5       6       7 
   7569   35993   43963   45592   40734   59788   40755  392620 
      8       9      10      11      12      13      14      15 
  63300   15387   61231   12231   19830   15489  303467  140283 
     16      17      18      19      20      21      22      23 
  17614    7371    9899    4454   35576   56336   18637   14852 
     24      25      26      27      28      29      30      31 
  12068   26315   14936   14248  391483   16661 1391960    2739 
     32      33      34      35      36      37      38      39 
   2205    1121    1818    1670     350     238     141      34 
     40      41      42      43      44      45      46      47 
    714      17     331      29      34     721      26      12 
     48      49      50      51      52      53      54      55 
     45      18     170      11      14      17      14      14 
     56      57      58      59      60      61      62      63 
    245       6       9       4    1703       9       3      12 
     64      65      66      67      68      69      70      71 
     20       8       3       4       6       1      30       2 
     72      73      75      76      77      78      80      82 
      7       3      54      13       3       3      49       1 
     83      84      85      86      87      88      89      90 
      5      73      13       1       1      13       3    3784 
     92      93      95      96      99     100     105     112 
      1       5       1       2       1      11       1       3 
    118     120     128     140     141     150     180     240 
      1       7       1       1       1       5      18       2 
    257     300     301     320     328     500     999 
      1       7       2       1       1       2       3 
dayssup_freq <- table(claims_demo$dayssup)


df_dayssup <- as.data.frame(dayssup_freq)
colnames(df_dayssup) <- c("dayssup", "frequency")

n <- nrow(df_dayssup)
part_size <- ceiling(n / 4)

df_dayssup_part1 <- df_dayssup[1:part_size, ]
df_dayssup_part2 <- df_dayssup[(part_size + 1):(2 * part_size), ]
df_dayssup_part3 <- df_dayssup[(2 * part_size + 1):(3 * part_size), ]
df_dayssup_part4 <- df_dayssup[(3 * part_size + 1):n, ]

plot1 <- ggplot(df_dayssup_part1, aes(x = as.factor(dayssup), y = frequency)) +
  geom_bar(stat = "identity", fill = "skyblue") +
  geom_text(aes(label = frequency), vjust = -0.3, size = 3.5) +
  labs(x = "Days Supply", y = "Frequency", title = "Histogram of Days Supply (Part 1)") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

plot2 <- ggplot(df_dayssup_part2, aes(x = as.factor(dayssup), y = frequency)) +
  geom_bar(stat = "identity", fill = "skyblue") +
  geom_text(aes(label = frequency), vjust = -0.3, size = 3.5) +
  labs(x = "Days Supply", y = "Frequency", title = "Histogram of Days Supply (Part 2)") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

plot3 <- ggplot(df_dayssup_part3, aes(x = as.factor(dayssup), y = frequency)) +
  geom_bar(stat = "identity", fill = "skyblue") +
  geom_text(aes(label = frequency), vjust = -0.3, size = 3.5) +
  labs(x = "Days Supply", y = "Frequency", title = "Histogram of Days Supply (Part 3)") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

plot4 <- ggplot(df_dayssup_part4, aes(x = as.factor(dayssup), y = frequency)) +
  geom_bar(stat = "identity", fill = "skyblue") +
  geom_text(aes(label = frequency), vjust = -0.3, size = 3.5) +
  labs(x = "Days Supply", y = "Frequency", title = "Histogram of Days Supply (Part 4)") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

print(plot1)

print(plot2)

print(plot3)

print(plot4)

table(claims_demo$quan)

   -90    -60    -58    -56    -28    -26    -12     -7      0 
     2      1      1      1      1      1      1      1  54831 
   0.5    0.7    0.9      1    1.1  1.111    1.3    1.5      2 
  2442      1      2  11794      3      3      2   2707  25628 
   2.5      3    3.5      4    4.5      5    5.5    5.6      6 
     1  22863      3  31202      1  26540      3      1  32881 
   6.5   6.99      7   7.03    7.5      8      9    9.5    9.9 
     1      1  86479      1      4  31446  15973      1      1 
    10   10.5     11     12   12.5     13   13.5     14     15 
 56783      9  45648  30625      4  11793      1 254479  87155 
    16  16.04     17   17.5     18     19     20     21     22 
 23352      1   7501      2  34466   4403  38616 106244  14743 
  22.5     23   23.8     24   24.5     25     26     27   27.5 
     5  16811      1  16383      1  17791   8446   6888      1 
    28     29   29.7     30     31     32     33     34     35 
189114   3517      1 345997   2176  12683   3809   4324  29121 
    36     37   37.5     38     39     40     41     42     43 
  7289   4231      1  12975   3054  15890   1593 102241   1562 
    44     45     46     47     48     49     50     51     52 
  4142 158437   3579    979   4478   9130  13049   1469   4969 
  52.5     53     54     55     56     57     58     59     60 
     4   7944   5445   3614 155650   1660   6326    649 509950 
    61     62     63     64     65     66     67     68     69 
   312   1463   9027   1249   2593   1517    753   3054    884 
    70     71     72     73     74     75     76     77     78 
 26972    241   1439    760    659  63298    543   1556   1256 
    79     80     81     82     83     84     85     86     87 
   209   3551   1063    609   1386  47881   1455    621   1660 
    88     89     90     91     92     93     94     95     96 
   737    114 271522    217    165    477     86    278    292 
    97     98     99    100    101    102    103    104    105 
    97   1543     78   3707     22   1566     16    131   6096 
   106    107    108    109    110    111    112    113    114 
    77     31    239     19    406     42   5471     76     92 
   115    116    117    118    119    120    121    122    123 
   182    260     23     48     31  56357     10     28     31 
   124    125    126    127    128    129    130    131    132 
   120     65    254     17     60     11    231      2     38 
   133    134    135    136    137    138    139    140    142 
     2     34    967     56      3     23      2    489     10 
   143    144    145    146    147    148    149    150    151 
     4     71     42      8     29     12      1   6053      1 
   152    153    154    155    156    157    158    159    160 
     7      5     37     10     11      3      4      5     64 
   162    163    164    165    166    167    168    170    172 
    12      1      9    113      7      1    399     31     10 
   173    174    175    176    177    178    179    180    181 
     1     14      7      5      4      3      1   7300      1 
   182    184    185    186    187    189    190    192    195 
    11      3      5      7      1      5     15     11     36 
   196    198    200    201    203    204    205    206    208 
   267      1    108      1      7     11      2      1      3 
   209    210    211    212    215    216    217    218    220 
     6    726      1      1      2      5      1      1     38 
   221    224    225    228    230    231    232    240    243 
     1    134    129      1      9      1     13   1757      2 
   244    245    246    250    252    255    256    257    260 
     2      1      1      8     17      3      1      1      8 
   261    264    265    268    269    270    275    280    290 
     1      1      1      1      1   1267      4     37     11 
   294    300    304    306    315    320    322    324    325 
     2    321      1      1      7      3      1      2      2 
   330    333    336    340    341    348    350    354    360 
    25      1     15      1      1      3      4      4    577 
   370    375    380    384    390    400    405    410    420 
     3      3     22      1     20      4      6      1     29 
   440    442    448    450    464    476    480    500    504 
     1      1      1     82      2      1     60      1      1 
   510    520    540    543    550    560    570    580    600 
     3      3     44      2      1     23      1      3    162 
   620    630    660    680    690    700    720    750    780 
     1      2      1      1      1      3      6     13      3 
   800    810    840    870    890    900    930    960    980 
     2     14     12      1      1     62      1      1      5 
  1000   1050   1060   1080   1100   1120   1200   1230   1800 
     3      5      2      1      1      5     20      1      2 
  2000   3000   5000   5829   7000   8000   9000  11000  12000 
    10     10      8      1     12      4      2      6     10 
 13000  14000  16000  21000  22000  23000  24000  25000  26000 
     2      5      6     20      9     12      1     18      1 
 27000  32000  33000  35000  38000  40000  41000  42000  43000 
     2     10      4      2      4      6      2     13      1 
 44000  45000  46000  50000  53000  56000  62000  63000  66000 
     2     63      3      2      6      1      1      3      2 
270000 
     3 
quantities_freq <- table(claims_demo$quan) 
df_quantities <- as.data.frame(quantities_freq)
colnames(df_quantities) <- c("quantities", "frequency")

n <- nrow(df_quantities)
part_size <- ceiling(n / 8)

df_quantities_part1 <- df_quantities[1:part_size, ]
df_quantities_part2 <- df_quantities[(part_size + 1):(2 * part_size), ]
df_quantities_part3 <- df_quantities[(2 * part_size + 1):(3 * part_size), ]
df_quantities_part4 <- df_quantities[(3 * part_size + 1):(4 * part_size), ]
df_quantities_part5 <- df_quantities[(4 * part_size + 1):(5 * part_size), ]
df_quantities_part6 <- df_quantities[(5 * part_size + 1):(6 * part_size), ]
df_quantities_part7 <- df_quantities[(6 * part_size + 1):(7 * part_size), ]
df_quantities_part8 <- df_quantities[(7 * part_size + 1):n, ]

plot1 <- ggplot(df_quantities_part1, aes(x = as.factor(quantities), y = frequency)) +
  geom_bar(stat = "identity", fill = "skyblue") +
  geom_text(aes(label = frequency), vjust = -0.3, size = 3.5) +
  labs(x = "Quantities", y = "Frequency", title = "Histogram of Quantities (Part 1)") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

plot2 <- ggplot(df_quantities_part2, aes(x = as.factor(quantities), y = frequency)) +
  geom_bar(stat = "identity", fill = "skyblue") +
  geom_text(aes(label = frequency), vjust = -0.3, size = 3.5) +
  labs(x = "Quantities", y = "Frequency", title = "Histogram of Quantities (Part 2)") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

plot3 <- ggplot(df_quantities_part3, aes(x = as.factor(quantities), y = frequency)) +
  geom_bar(stat = "identity", fill = "skyblue") +
  geom_text(aes(label = frequency), vjust = -0.3, size = 3.5) +
  labs(x = "Quantities", y = "Frequency", title = "Histogram of Quantities (Part 3)") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

plot4 <- ggplot(df_quantities_part4, aes(x = as.factor(quantities), y = frequency)) +
  geom_bar(stat = "identity", fill = "skyblue") +
  geom_text(aes(label = frequency), vjust = -0.3, size = 3.5) +
  labs(x = "Quantities", y = "Frequency", title = "Histogram of Quantities (Part 4)") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

plot5 <- ggplot(df_quantities_part5, aes(x = as.factor(quantities), y = frequency)) +
  geom_bar(stat = "identity", fill = "skyblue") +
  geom_text(aes(label = frequency), vjust = -0.3, size = 3.5) +
  labs(x = "Quantities", y = "Frequency", title = "Histogram of Quantities (Part 5)") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

plot6 <- ggplot(df_quantities_part6, aes(x = as.factor(quantities), y = frequency)) +
  geom_bar(stat = "identity", fill = "skyblue") +
  geom_text(aes(label = frequency), vjust = -0.3, size = 3.5) +
  labs(x = "Quantities", y = "Frequency", title = "Histogram of Quantities (Part 6)") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

plot7 <- ggplot(df_quantities_part7, aes(x = as.factor(quantities), y = frequency)) +
  geom_bar(stat = "identity", fill = "skyblue") +
  geom_text(aes(label = frequency), vjust = -0.3, size = 3.5) +
  labs(x = "Quantities", y = "Frequency", title = "Histogram of Quantities (Part 7)") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

plot8 <- ggplot(df_quantities_part8, aes(x = as.factor(quantities), y = frequency)) +
  geom_bar(stat = "identity", fill = "skyblue") +
  geom_text(aes(label = frequency), vjust = -0.3, size = 3.5) +
  labs(x = "Quantities", y = "Frequency", title = "Histogram of Quantities (Part 8)") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

print(plot1)

print(plot2)

print(plot3)

print(plot4)

print(plot5)

print(plot6)

print(plot7)

print(plot8)

Summarize buprenorphine prescriptions by year

prescriptions_by_year <- claims_demo %>%
  group_by(year) %>%
  summarise(count = n())

#1. Bar Graph of Counts by Year
# Plot the bar graph
ggplot(prescriptions_by_year, aes(x = year, y = count)) +
  geom_bar(stat = "identity") +
  labs(title = "Number of Prescriptions by Year",
       x = "Year",
       y = "Number of Prescriptions") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

From 2006 to 2013, there was a steady increase in the number of prescriptions, peaking in 2013 and 2014 with over 300,000 prescriptions each year.

This rise suggests a growing trend in prescription rates or improved access to healthcare during these years.

However, following 2014, there is a notable decline in the number of prescriptions, reaching its lowest point around 2019. This decline may be attributed to changes in healthcare policies.

In the subsequent years, there is a slight recovery in 2021 and 2022, indicating a resurgence in prescription rates, but this is followed by a sharp decrease in 2023. This could be influenced by external factors such as changes in healthcare regulations, economic conditions, or the impact of global events like the COVID-19 pandemic.

Summarize buprenorphine prescriptions by year, Stratified by Sex

Filter the data to include only entries with sex “F” and “M”

fig1_filtered <- claims_demo %>%
  filter(der_sex %in% c("F", "M"))

# Summarize the data by year and sex
prescriptions_by_year_sex <- fig1_filtered %>%
  group_by(year, der_sex) %>%
  summarise(count = n())
`summarise()` has grouped output by 'year'. You can override using the `.groups` argument.
# Plot the bar graph
ggplot(prescriptions_by_year_sex, aes(x = year, y = count, fill = der_sex)) +
  geom_bar(stat = "identity", position = "dodge") +
  labs(title = "Number of Prescriptions by Year, Stratified by Sex",
       x = "Year",
       y = "Number of Prescriptions",
       fill = "Sex") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

The second bar graph shows the number of prescriptions by year, stratified by sex (F and M). It highlights several important trends and differences between male and female prescription rates. Overall, the number of prescriptions for both sexes follows a similar pattern, with an increase from 2006, peaking around 2013 and 2014, followed by a decline.

Throughout the years, males consistently have higher prescription counts compared to females. The peak years of 2013 and 2014 show the most significant differences, with males having substantially more prescriptions than females. After 2014, the number of prescriptions for both sexes declines, reaching a low point around 2019.

This graph indicates that while the overall prescription trends are similar for both males and females, males consistently receive more prescriptions than females across all years.

create a map of prescriptions by US state

fig2<-claims_demo %>% select(pat_state, year) 
write.csv(fig2, "fig2.csv")  

prescriptions_by_state <- fig2 %>%
  group_by(pat_state) %>%
  summarise(total_prescriptions = n())

head(prescriptions_by_state)
prescriptions_by_state <- as.data.frame(prescriptions_by_state)
prescriptions_by_state<-prescriptions_by_state[-1,]
colnames(prescriptions_by_state)[1]<-"state"

plot_usmap(data = prescriptions_by_state, values = "total_prescriptions", color = "white") +
  scale_fill_continuous(name = "Total Prescriptions", label = scales::comma) +
  labs(title = "Total Number of Prescriptions by US State") +
  theme(legend.position = "right")

create a map of Total Prescriptions by US State

state_data <- merge(prescriptions_by_state, state_centers, by.x = "state", by.y = "state")

# Total prescriptions plot using plotly
total_prescriptions_plot <- plot_usmap(data = prescriptions_by_state, values = "total_prescriptions", color = "white") +
  geom_text(data = state_data, aes(x = x, y = y, label = state), size = 3, hjust = 0.5, color = "black") +
  scale_fill_gradientn(name = "Total Prescriptions", colors = c("blue", "green", "yellow", "red"), labels = scales::comma, 
                       breaks = seq(0, max(prescriptions_by_state$total_prescriptions), length.out = 6)) +
  labs(title = "Total Number of Prescriptions by US State") +
  theme(legend.position = "right")

# Convert to plotly object
ggplotly(total_prescriptions_plot)

Create a Shiny App

ui <- fluidPage(
  titlePanel("Number of Prescriptions by US State"),
  tabsetPanel(
    tabPanel("Total",
             plotOutput("staticMap")
    ),
    tabPanel("Yearly",
             sidebarLayout(
               sidebarPanel(
                 selectInput("year", "Select Year:", choices = unique(prescriptions_by_state_year$year))
               ),
               mainPanel(
                 plotlyOutput("usMap")
               )
             )
    ),
    tabPanel("Product Trends",
             plotOutput("productTrendGraph")
    )
  )
)

server <- function(input, output) {
  output$staticMap <- renderPlot({
    state_data <- merge(prescriptions_by_state, state_centers, by.x = "state", by.y = "state")
    
    plot_usmap(data = prescriptions_by_state, values = "total_prescriptions", color = "white") +
      geom_text(data = state_data, aes(x = x, y = y, label = state), size = 3, hjust = 0.5, color = "black") +
      scale_fill_gradientn(name = "Total Prescriptions", colors = c("blue", "green", "yellow", "red"), labels = scales::comma, 
                           breaks = seq(0, max(prescriptions_by_state$total_prescriptions), length.out = 6)) +
      labs(title = "Total Number of Prescriptions by US State") +
      theme(legend.position = "right")
  })
  
  output$usMap <- renderPlotly({
    data_year <- prescriptions_by_state_year %>%
      filter(year == input$year)
    
    state_data_year <- merge(data_year, state_centers, by = "state")
    
    p <- plot_usmap(data = data_year, values = "total_prescriptions", color = "white") +
      geom_text(data = state_data_year, aes(x = x, y = y, label = state), size = 3, hjust = 0.5, color = "black") +
      scale_fill_gradientn(name = paste("Prescriptions in", input$year), colors = c("blue", "green", "yellow", "red"), labels = scales::comma, 
                           breaks = seq(0, max(data_year$total_prescriptions), length.out = 6)) +
      labs(title = paste("Number of Buprenorphine OUD Prescriptions by US State in", input$year)) +
      theme(legend.position = "right")
    
    ggplotly(p)
  })
  
  output$productTrendGraph <- renderPlot({
    ggplot(product_data, aes(x = year, y = percentage, color = product_name)) +
      geom_line(size = 1.2) +
      scale_color_viridis(discrete = TRUE) + 
      labs(title = "Percentage of Each Product Over Time (2006-2023)",
           x = "Year",
           y = "Percentage of Total Prescriptions",
           color = "Product") +
      theme_minimal() +
      theme(legend.position = "right", legend.title = element_text(size = 10),
            legend.text = element_text(size = 8))
  })
}

shinyApp(ui = ui, server = server)

summarizing the final cohort dataset

rectype_summary <- summary(claims_demo$rectype)
dosage_form_nm_summary <- summary(claims_demo$dosage_form_nm)
route_summary <- summary(claims_demo$route)
strength_summary <- summary(claims_demo$strength)

rectype_plot <- ggplot(claims_demo, aes(x = factor(rectype))) +
  geom_bar(fill = 'skyblue', color = 'black') +
  labs(title = 'Distribution of Rectype', x = 'Rectype', y = 'Frequency') +
  theme_minimal()

dosage_form_nm_plot <- ggplot(claims_demo, aes(x = factor(dosage_form_nm))) +
  geom_bar(fill = 'salmon', color = 'black') +
  labs(title = 'Distribution of Dosage Form Name', x = 'Dosage Form Name', y = 'Frequency') +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))


route_plot <- ggplot(claims_demo, aes(x = factor(route))) +
  geom_bar(fill = 'lightgreen', color = 'black') +
  labs(title = 'Distribution of Route', x = 'Route', y = 'Frequency') +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))


strength_plot <- ggplot(claims_demo, aes(x = factor(strength))) +
  geom_bar(fill = 'lightblue', color = 'black') +
  labs(title = 'Distribution of Strength', x = 'Strength', y = 'Frequency') +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

rectype_plot 

dosage_form_nm_plot 

route_plot 

strength_plot 

colnames(claims_demo)

selected_data <- claims_demo %>% select(pat_id, der_sex, pat_region, pat_state, yob_group, zip3_group)
Error in `select()`:
! Can't subset columns that don't exist.
✖ Column `yob_group` doesn't exist.
Backtrace:
 1. claims_demo %>% ...
 3. dplyr:::select.data.frame(., pat_id, der_sex, pat_region, pat_state, yob_group, zip3_group)
LS0tCnRpdGxlOiBBSU0tQUhFQUQgUHJvamVjdCAKc3VidGl0bGU6IEV4cGxvcmF0b3J5IGRhdGEgYW5hbHlzaXMgCmF1dGhvcjogV2FucnUgR3VvIGFuZCBDaWNpIEJhdWVyCmRhdGU6ICJMYXN0IGNvbXBpbGVkIG9uIGByIGZvcm1hdChTeXMudGltZSgpLCAnJUIgJWQsICVZJylgIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazogCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiA0CiAgICB0b2NfZmxvYXQ6IHllcwotLS0KCiMjIERhdGEgZmlsdGVyaW5nClBhdGllbnQgRW5yb2xsbWVudCBGaWx0ZXJpbmc6IENsYWltcyBkYXRhIHdlcmUgZmlsdGVyZWQgdG8gaW5jbHVkZSBvbmx5IHBhdGllbnRzIHdpdGggZW5yb2xsbWVudCBwZXJpb2RzIGV4Y2VlZGluZyAxMiBtb250aHMuIFRoaXMgY3JpdGVyaW9uIHdhcyBzZXQgdG8gZW5zdXJlIHRoYXQgdGhlIGRhdGEgcmVwcmVzZW50ZWQgYSBzdWZmaWNpZW50bHkgbG9uZyBwZXJpb2QgdG8gYW5hbHl6ZSB0cmVhdG1lbnQgcGF0dGVybnMgYW5kIG91dGNvbWVzIGFjY3VyYXRlbHkuCgpMaW5raW5nIHJ4X2luZm9ybWF0aW9uOiBUaGUgcnhfaW5mb3JtYXRpb24gZGF0YSB3YXMgbGlua2VkIHRvIHRoZSBjbGFpbXMgZGF0YSB1c2luZyBOYXRpb25hbCBEcnVnIENvZGVzIChORENzKS4gVGhpcyBsaW5rYWdlIHdhcyBlc3NlbnRpYWwgZm9yIGludGVncmF0aW5nIHByZXNjcmlwdGlvbiBpbmZvcm1hdGlvbiB3aXRoIHRoZSBjbGFpbXMgZGF0YS4KCklkZW50aWZ5aW5nIEJ1cHJlbm9ycGhpbmUgT1VEIENvaG9ydDogVGhlIGJ1cHJlbm9ycGhpbmUgb3Bpb2lkIHVzZSBkaXNvcmRlciAoT1VEKSBjb2hvcnQgd2FzIGlkZW50aWZpZWQgdXNpbmcgdGhlIFVuaXZlcnNhbCBTZXJ2aWNlIENvZGUgKHVzY19jZCkgb2YgNzg0MzAsIHdoaWNoIGNvcnJlc3BvbmRzIHRvIOKAmERydWcgRGVwZW5kZW5jZeKAmS4KCkNodW5rIFByb2Nlc3NpbmcgRnVuY3Rpb246IEEgY3VzdG9tIGZ1bmN0aW9uIHdhcyB3cml0dGVuIHRvIHByb2Nlc3MgZWFjaCBjaHVuayBvZiBkYXRhIHNlcGFyYXRlbHkuIFRoaXMgYXBwcm9hY2ggZW5zdXJlZCB0aGF0IHRoZSBkYXRhc2V0IHdhcyBoYW5kbGVkIGVmZmljaWVudGx5IGFuZCBlZmZlY3RpdmVseSwgZXNwZWNpYWxseSBnaXZlbiB0aGUgcG90ZW50aWFsbHkgbGFyZ2Ugc2l6ZSBvZiB0aGUgY2xhaW1zIGRhdGEuIFRoZSBwcm9jZXNzZWQgY2h1bmtzIHdlcmUgdGhlbiBjb21iaW5lZCBpbnRvIGEgc2luZ2xlIGRhdGFzZXQuCgpEdXBsaWNhdGUgUmVtb3ZhbDogRHVwbGljYXRlIGVudHJpZXMgd2VyZSBtZXRpY3Vsb3VzbHkgcmVtb3ZlZCB0byBwcmV2ZW50IHJlZHVuZGFuY3kgYW5kIGVuc3VyZSB0aGUgYWNjdXJhY3kgb2YgdGhlIGRhdGFzZXQuCgpKb2luaW5nIHdpdGggRGVtb2dyYXBoaWNzOiBUaGUgcmVzdWx0aW5nIGRhdGEgZnJhbWUgd2FzIGpvaW5lZCB3aXRoIGRlbW9ncmFwaGljIGluZm9ybWF0aW9uIHRvIGNyZWF0ZSB0aGUgZmluYWwgZGF0YXNldCwgbmFtZWQg4oCYY2xhaW1zX2RlbW/igJkuIFRoaXMgZmluYWwgZGF0YXNldCBpbnRlZ3JhdGVkIGFsbCBuZWNlc3NhcnkgZGF0YSBlbGVtZW50cywgaW5jbHVkaW5nIGNsYWltcywgcHJlc2NyaXB0aW9ucywgYW5kIHBhdGllbnQgZGVtb2dyYXBoaWNzLCBwcm92aWRpbmcgYSBjb21wcmVoZW5zaXZlIGZvdW5kYXRpb24gZm9yIHN1YnNlcXVlbnQgYW5hbHlzZXMuCgpUaGUgZmluYWwgY29ob3J0IG5vdyBoYXMgMzM1ODg1MCBjbGFpbXMgdG90YWwgYW5kIDE4Nzc5MCBpbmRpdmlkdWFsIHBhdGllbnRzLiAKCiMjIERhdGEgbGlua2FnZQpMaW5raW5nIERlbW9ncmFwaGljIERhdGEgd2l0aCBDbGFpbXM6IFRoZSBkZW1vZ3JhcGhpYyBkYXRhIHdhcyBsaW5rZWQgdG8gdGhlIGNsYWltcyBkYXRhIHZpYSBwYXRpZW50IElEcy4gVGhpcyBzdGVwIGVuc3VyZWQgdGhhdCBlYWNoIGNsYWltIGNvdWxkIGJlIGFzc29jaWF0ZWQgd2l0aCB0aGUgY29ycmVzcG9uZGluZyBwYXRpZW504oCZcyBkZW1vZ3JhcGhpYyBpbmZvcm1hdGlvbi4KCkxpbmtpbmcgUlggSW5mb3JtYXRpb24gd2l0aCBDbGFpbXM6IFRoZSByeF9pbmZvcm1hdGlvbiBkYXRhIHdhcyBsaW5rZWQgdG8gdGhlIGNsYWltcyBkYXRhIHVzaW5nIHRoZSBORENzLiBUaGlzIGxpbmthZ2Ugd2FzIGVzc2VudGlhbCBmb3IgYXNzb2NpYXRpbmcgc3BlY2lmaWMgbWVkaWNhdGlvbnMgd2l0aCBwYXRpZW50IGNsYWltcy4KCidjbGFpbXNfZGVtbycgaXMgdGhlIGZpbmFsIGRhdGFzZXQuIAoKYGBge3J9CmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZGF0YS50YWJsZSkKbGlicmFyeShnZ3Bsb3QyKSAKbGlicmFyeShwbG90bHkpCmxpYnJhcnkodXNtYXApCmxpYnJhcnkoZ3JpZEV4dHJhKQpsaWJyYXJ5KHNoaW55KQpgYGAKCgpgYGB7cn0KZmlsdGVyX2NvaG9ydDwtZnVuY3Rpb24oZGYpIHsKY2xhc3MoZGYkbmRjKSA8LSAiY2hhcmFjdGVyIgpjbGFzcyhyeF9pbmZvcm1hdGlvbiRuZGMpIDwtICJjaGFyYWN0ZXIiCmNsYWltc19yeCA8LSBkZiAlPiUgCiAgbGVmdF9qb2luKC4scnhfaW5mb3JtYXRpb24sIGJ5ID0gIm5kYyIpCmtleXdvcmRzIDwtIGMoIkJVTkFWQUlMIiwgIkJVUFJFTk9SUEhJTkUvTkFMT1giLCAiQlVQUkVOT1JQSElORSBIQ0wiLCAiQlVQUkVOT1JQSElORSBIQ0wvTkFMT1hPTiIsICJCVVBSRU5PUlBISU5FIEhZRFJPQ0hMT1JJIiwgIlBST0JVUEhJTkUgSU1QTEFOVCBLSVQiLCAiU1VCTE9DQURFIiwgIlNVQk9YT05FIiwgIlNVQlVURVgiLCAiWlVCU09MViIpIApwYXR0ZXJuPC1wYXN0ZShrZXl3b3Jkcyxjb2xsYXBzZT0ifCIpCmNsYWltc19yeGIgPC1jbGFpbXNfcnggJT4lIAogIGZpbHRlcihncmVwbChwYXR0ZXJuLCBwcm9kdWN0X25hbWUsIGlnbm9yZS5jYXNlPVRSVUUpIHwgZ3JlcGwocGF0dGVybiwgZ2VuZXJpY19uYW1lLCBpZ25vcmUuY2FzZT1UUlVFKSkKY2xhaW1zX3J4Yl8xMm1vbnRocyA8LSBjbGFpbXNfcnhiICU+JSAKICBmaWx0ZXIoLiRwYXRfaWQgJWluJSBwYXRpZW50c19mdWxsX2Vucm9sbCkKZHVwbGljYXRlczwtYXBwbHkoY2xhaW1zX3J4Yl8xMm1vbnRocywxLGZ1bmN0aW9uKHJvdykgbGVuZ3RoKHVuaXF1ZShyb3cpPT0xKSkKY2xhaW1zX3J4Yl8xMm1vbnRoczwtY2xhaW1zX3J4Yl8xMm1vbnRoc1shZHVwbGljYXRlcywgXQpjbGFpbXNfcnhiXzEybW88LWNsYWltc19yeGJfMTJtb250aHNbY2xhaW1zX3J4Yl8xMm1vbnRocyR1c2NfY2QgPT0gIjc4MzQwIiwgXQpmd3JpdGUoY2xhaW1zX3J4Yl8xMm1vLCAiZGYyX2ZpbHRlcmVkIikKY2xhaW1zX3J4Yl8xMm1vMjwtY2xhaW1zX3J4Yl8xMm1vICU+JSBzZWxlY3QocGF0X2lkLCBkYXlzc3VwLCBxdWFuLCBmcm9tX2R0LCB0b19kdCwgbmRjLCBwcm9jX2NkZSwgZGlhZ3ByY19pbmQsIGRpYWcxLCBkaWFnMiwgZGlhZzMsIGRpYWc0LCBkaWFnNSwgZGlhZzYsIGRpYWc3LCBkaWFnOCkgJT4lIGFycmFuZ2UocGF0X2lkKQpmd3JpdGUoY2xhaW1zX3J4Yl8xMm1vMiwgImRmMl9maWx0ZXJlZF9zZWxlY3RlZCIpIApyZXR1cm4oaGVhZChjbGFpbXNfcnhiXzEybW8yKSkgCn0gCmZpbHRlcl9jb2hvcnQoZDIpCmBgYAoKYGBge3IsaW5jbHVkZT1GQUxTRX0Kc2V0d2QoIi9Vc2Vycy93YW5ydWcvRG9jdW1lbnRzIikgCmNsYWltc19kZW1vPC1yZWFkLmNzdigiY2xhaW1zX2RlbW8uY3N2IikgCmhlYWQoY2xhaW1zX2RlbW8pCmZpZzE8LWNsYWltc19kZW1vICU+JSBzZWxlY3QoZGVyX3NleCwgeWVhcikgCndyaXRlLmNzdihmaWcxLCAiZmlnMS5jc3YiKSAgCmBgYAoKIyMgbWlzc2luZ25lc3MgY2hlY2sgCmBgYHtyfQptaXNzaW5nbmVzcyA8LSBjb2xTdW1zKGlzLm5hKGNsYWltc19kZW1vWyxjKDE6MjApXSkpIC8gbnJvdyhjbGFpbXNfZGVtb1ssYygxOjIwKV0pICogMTAwCgptaXNzaW5nbmVzc19kZiA8LSBkYXRhLmZyYW1lKAogIENvbHVtbiA9IG5hbWVzKG1pc3NpbmduZXNzKSwKICBNaXNzaW5nUGVyY2VudGFnZSA9IG1pc3NpbmduZXNzCikgJT4lCiAgYXJyYW5nZShkZXNjKE1pc3NpbmdQZXJjZW50YWdlKSkKCnAgPC0gcGxvdF9seSgKICBkYXRhID0gbWlzc2luZ25lc3NfZGYsCiAgeCA9IH5NaXNzaW5nUGVyY2VudGFnZSwKICB5ID0gfnJlb3JkZXIoQ29sdW1uLCBNaXNzaW5nUGVyY2VudGFnZSksCiAgdHlwZSA9ICdiYXInLAogIG9yaWVudGF0aW9uID0gJ2gnLAogIHRleHQgPSB+cGFzdGUoIk1pc3Npbmc6ICIsIHJvdW5kKE1pc3NpbmdQZXJjZW50YWdlLCAyKSwgIiUiKSwKICBob3ZlcmluZm8gPSAndGV4dCcsCiAgbWFya2VyID0gbGlzdChjb2xvciA9ICdzdGVlbGJsdWUnKQopICU+JQogIGxheW91dCgKICAgIHRpdGxlID0gJ1BlcmNlbnRhZ2Ugb2YgTWlzc2luZyBWYWx1ZXMgYnkgQ29sdW1uJywKICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICdNaXNzaW5nIFBlcmNlbnRhZ2UgKCUpJyksCiAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAnQ29sdW1uJywgYXV0b21hcmdpbiA9IFRSVUUsIHRpY2tmb250ID0gbGlzdChzaXplID0gMTApKSwKICAgIG1hcmdpbiA9IGxpc3QobCA9IDIwMCwgciA9IDUwLCB0ID0gNTAsIGIgPSA1MCkgICMgQWRqdXN0IG1hcmdpbnMgdG8gZml0IGxhYmVscwogICkKCnAKYGBgCgpgYGB7cn0KbWlzc2luZ25lc3MgPC0gY29sU3Vtcyhpcy5uYShjbGFpbXNfZGVtb1ssLWMoMToyMCldKSkgLyBucm93KGNsYWltc19kZW1vWywtYygxOjIwKV0pICogMTAwCgptaXNzaW5nbmVzc19kZiA8LSBkYXRhLmZyYW1lKAogIENvbHVtbiA9IG5hbWVzKG1pc3NpbmduZXNzKSwKICBNaXNzaW5nUGVyY2VudGFnZSA9IG1pc3NpbmduZXNzCikgJT4lCiAgYXJyYW5nZShkZXNjKE1pc3NpbmdQZXJjZW50YWdlKSkKCnAgPC0gcGxvdF9seSgKICBkYXRhID0gbWlzc2luZ25lc3NfZGYsCiAgeCA9IH5NaXNzaW5nUGVyY2VudGFnZSwKICB5ID0gfnJlb3JkZXIoQ29sdW1uLCBNaXNzaW5nUGVyY2VudGFnZSksCiAgdHlwZSA9ICdiYXInLAogIG9yaWVudGF0aW9uID0gJ2gnLAogIHRleHQgPSB+cGFzdGUoIk1pc3Npbmc6ICIsIHJvdW5kKE1pc3NpbmdQZXJjZW50YWdlLCAyKSwgIiUiKSwKICBob3ZlcmluZm8gPSAndGV4dCcsCiAgbWFya2VyID0gbGlzdChjb2xvciA9ICdzdGVlbGJsdWUnKQopICU+JQogIGxheW91dCgKICAgIHRpdGxlID0gJ1BlcmNlbnRhZ2Ugb2YgTWlzc2luZyBWYWx1ZXMgYnkgQ29sdW1uJywKICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICdNaXNzaW5nIFBlcmNlbnRhZ2UgKCUpJyksCiAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAnQ29sdW1uJywgYXV0b21hcmdpbiA9IFRSVUUsIHRpY2tmb250ID0gbGlzdChzaXplID0gMTApKSwKICAgIG1hcmdpbiA9IGxpc3QobCA9IDIwMCwgciA9IDUwLCB0ID0gNTAsIGIgPSA1MCkgICMgQWRqdXN0IG1hcmdpbnMgdG8gZml0IGxhYmVscwogICkKCnAKYGBgClNpbmNlIGRpYWc5LWRpYWcxMiBhcmUgbWlzc2luZyAxMDAlLCB3ZSBjb3VsZCByZW1vdmUgdGhvc2UgY29sdW1ucyAKYGBge3J9CmNsYWltc19kZW1vPC0gY2xhaW1zX2RlbW8gJT4lCiAgc2VsZWN0KC1kaWFnOSwgLWRpYWcxMCwgLWRpYWcxMSwgLWRpYWcxMikKYGBgClNpbmNlIGRpYWc5LWRpYWcxMiBhcmUgbWlzc2luZyAxMDAlLCB3ZSBjb3VsZCByZW1vdmUgdGhvc2UgY29sdW1ucyAKCkdyb3VwIGJ5IHBhdGllbnQgSUQgYW5kIGRhdGVzIGNsYWltZWQgCmBgYHtyfQpjbGFpbXNfZGVtbyA8LSBjbGFpbXNfZGVtbyAlPiUgYXJyYW5nZShwYXRfaWQsIGZyb21fZHQpICU+JSBncm91cF9ieShwYXRfaWQpIApgYGAKCmBgYHtyfQpjbGFpbXNfZGVtbyA8LSBjbGFpbXNfZGVtbyAlPiUKICBtdXRhdGUoeWVhciA9IHllYXIoeW1kKGZyb21fZHQpKSkKYGBgCiMjIFRoZSBmaW5hbCBjb2hvcnQgcmVhZHkgZm9yIGlkZW50aWZ5aW5nICBlcGlzb2RlcyAgCmBgYHtyfQpoZWFkKGNsYWltc19kZW1vLDEwMCkKYGBgCgpTdW1tYXJpZXMgb2YgRGF5cyBwcmVzY3JpYmVkIGFuZCBxdWFudGl0eSBwcmVzY3JpYmVkIAoKYGBge3J9CnRhYmxlKGNsYWltc19kZW1vJGRheXNzdXApCgpkYXlzc3VwX2ZyZXEgPC0gdGFibGUoY2xhaW1zX2RlbW8kZGF5c3N1cCkKCgpkZl9kYXlzc3VwIDwtIGFzLmRhdGEuZnJhbWUoZGF5c3N1cF9mcmVxKQpjb2xuYW1lcyhkZl9kYXlzc3VwKSA8LSBjKCJkYXlzc3VwIiwgImZyZXF1ZW5jeSIpCgpuIDwtIG5yb3coZGZfZGF5c3N1cCkKcGFydF9zaXplIDwtIGNlaWxpbmcobiAvIDQpCgpkZl9kYXlzc3VwX3BhcnQxIDwtIGRmX2RheXNzdXBbMTpwYXJ0X3NpemUsIF0KZGZfZGF5c3N1cF9wYXJ0MiA8LSBkZl9kYXlzc3VwWyhwYXJ0X3NpemUgKyAxKTooMiAqIHBhcnRfc2l6ZSksIF0KZGZfZGF5c3N1cF9wYXJ0MyA8LSBkZl9kYXlzc3VwWygyICogcGFydF9zaXplICsgMSk6KDMgKiBwYXJ0X3NpemUpLCBdCmRmX2RheXNzdXBfcGFydDQgPC0gZGZfZGF5c3N1cFsoMyAqIHBhcnRfc2l6ZSArIDEpOm4sIF0KCnBsb3QxIDwtIGdncGxvdChkZl9kYXlzc3VwX3BhcnQxLCBhZXMoeCA9IGFzLmZhY3RvcihkYXlzc3VwKSwgeSA9IGZyZXF1ZW5jeSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJza3libHVlIikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBmcmVxdWVuY3kpLCB2anVzdCA9IC0wLjMsIHNpemUgPSAzLjUpICsKICBsYWJzKHggPSAiRGF5cyBTdXBwbHkiLCB5ID0gIkZyZXF1ZW5jeSIsIHRpdGxlID0gIkhpc3RvZ3JhbSBvZiBEYXlzIFN1cHBseSAoUGFydCAxKSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCgpwbG90MiA8LSBnZ3Bsb3QoZGZfZGF5c3N1cF9wYXJ0MiwgYWVzKHggPSBhcy5mYWN0b3IoZGF5c3N1cCksIHkgPSBmcmVxdWVuY3kpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAic2t5Ymx1ZSIpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gZnJlcXVlbmN5KSwgdmp1c3QgPSAtMC4zLCBzaXplID0gMy41KSArCiAgbGFicyh4ID0gIkRheXMgU3VwcGx5IiwgeSA9ICJGcmVxdWVuY3kiLCB0aXRsZSA9ICJIaXN0b2dyYW0gb2YgRGF5cyBTdXBwbHkgKFBhcnQgMikiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQoKcGxvdDMgPC0gZ2dwbG90KGRmX2RheXNzdXBfcGFydDMsIGFlcyh4ID0gYXMuZmFjdG9yKGRheXNzdXApLCB5ID0gZnJlcXVlbmN5KSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gInNreWJsdWUiKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGZyZXF1ZW5jeSksIHZqdXN0ID0gLTAuMywgc2l6ZSA9IDMuNSkgKwogIGxhYnMoeCA9ICJEYXlzIFN1cHBseSIsIHkgPSAiRnJlcXVlbmN5IiwgdGl0bGUgPSAiSGlzdG9ncmFtIG9mIERheXMgU3VwcGx5IChQYXJ0IDMpIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKCnBsb3Q0IDwtIGdncGxvdChkZl9kYXlzc3VwX3BhcnQ0LCBhZXMoeCA9IGFzLmZhY3RvcihkYXlzc3VwKSwgeSA9IGZyZXF1ZW5jeSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJza3libHVlIikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBmcmVxdWVuY3kpLCB2anVzdCA9IC0wLjMsIHNpemUgPSAzLjUpICsKICBsYWJzKHggPSAiRGF5cyBTdXBwbHkiLCB5ID0gIkZyZXF1ZW5jeSIsIHRpdGxlID0gIkhpc3RvZ3JhbSBvZiBEYXlzIFN1cHBseSAoUGFydCA0KSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCgpwcmludChwbG90MSkKcHJpbnQocGxvdDIpCnByaW50KHBsb3QzKQpwcmludChwbG90NCkKCmBgYAoKYGBge3J9CnRhYmxlKGNsYWltc19kZW1vJHF1YW4pCgpxdWFudGl0aWVzX2ZyZXEgPC0gdGFibGUoY2xhaW1zX2RlbW8kcXVhbikgCmRmX3F1YW50aXRpZXMgPC0gYXMuZGF0YS5mcmFtZShxdWFudGl0aWVzX2ZyZXEpCmNvbG5hbWVzKGRmX3F1YW50aXRpZXMpIDwtIGMoInF1YW50aXRpZXMiLCAiZnJlcXVlbmN5IikKCm4gPC0gbnJvdyhkZl9xdWFudGl0aWVzKQpwYXJ0X3NpemUgPC0gY2VpbGluZyhuIC8gOCkKCmRmX3F1YW50aXRpZXNfcGFydDEgPC0gZGZfcXVhbnRpdGllc1sxOnBhcnRfc2l6ZSwgXQpkZl9xdWFudGl0aWVzX3BhcnQyIDwtIGRmX3F1YW50aXRpZXNbKHBhcnRfc2l6ZSArIDEpOigyICogcGFydF9zaXplKSwgXQpkZl9xdWFudGl0aWVzX3BhcnQzIDwtIGRmX3F1YW50aXRpZXNbKDIgKiBwYXJ0X3NpemUgKyAxKTooMyAqIHBhcnRfc2l6ZSksIF0KZGZfcXVhbnRpdGllc19wYXJ0NCA8LSBkZl9xdWFudGl0aWVzWygzICogcGFydF9zaXplICsgMSk6KDQgKiBwYXJ0X3NpemUpLCBdCmRmX3F1YW50aXRpZXNfcGFydDUgPC0gZGZfcXVhbnRpdGllc1soNCAqIHBhcnRfc2l6ZSArIDEpOig1ICogcGFydF9zaXplKSwgXQpkZl9xdWFudGl0aWVzX3BhcnQ2IDwtIGRmX3F1YW50aXRpZXNbKDUgKiBwYXJ0X3NpemUgKyAxKTooNiAqIHBhcnRfc2l6ZSksIF0KZGZfcXVhbnRpdGllc19wYXJ0NyA8LSBkZl9xdWFudGl0aWVzWyg2ICogcGFydF9zaXplICsgMSk6KDcgKiBwYXJ0X3NpemUpLCBdCmRmX3F1YW50aXRpZXNfcGFydDggPC0gZGZfcXVhbnRpdGllc1soNyAqIHBhcnRfc2l6ZSArIDEpOm4sIF0KCnBsb3QxIDwtIGdncGxvdChkZl9xdWFudGl0aWVzX3BhcnQxLCBhZXMoeCA9IGFzLmZhY3RvcihxdWFudGl0aWVzKSwgeSA9IGZyZXF1ZW5jeSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJza3libHVlIikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBmcmVxdWVuY3kpLCB2anVzdCA9IC0wLjMsIHNpemUgPSAzLjUpICsKICBsYWJzKHggPSAiUXVhbnRpdGllcyIsIHkgPSAiRnJlcXVlbmN5IiwgdGl0bGUgPSAiSGlzdG9ncmFtIG9mIFF1YW50aXRpZXMgKFBhcnQgMSkiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQoKcGxvdDIgPC0gZ2dwbG90KGRmX3F1YW50aXRpZXNfcGFydDIsIGFlcyh4ID0gYXMuZmFjdG9yKHF1YW50aXRpZXMpLCB5ID0gZnJlcXVlbmN5KSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gInNreWJsdWUiKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGZyZXF1ZW5jeSksIHZqdXN0ID0gLTAuMywgc2l6ZSA9IDMuNSkgKwogIGxhYnMoeCA9ICJRdWFudGl0aWVzIiwgeSA9ICJGcmVxdWVuY3kiLCB0aXRsZSA9ICJIaXN0b2dyYW0gb2YgUXVhbnRpdGllcyAoUGFydCAyKSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCgpwbG90MyA8LSBnZ3Bsb3QoZGZfcXVhbnRpdGllc19wYXJ0MywgYWVzKHggPSBhcy5mYWN0b3IocXVhbnRpdGllcyksIHkgPSBmcmVxdWVuY3kpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAic2t5Ymx1ZSIpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gZnJlcXVlbmN5KSwgdmp1c3QgPSAtMC4zLCBzaXplID0gMy41KSArCiAgbGFicyh4ID0gIlF1YW50aXRpZXMiLCB5ID0gIkZyZXF1ZW5jeSIsIHRpdGxlID0gIkhpc3RvZ3JhbSBvZiBRdWFudGl0aWVzIChQYXJ0IDMpIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKCnBsb3Q0IDwtIGdncGxvdChkZl9xdWFudGl0aWVzX3BhcnQ0LCBhZXMoeCA9IGFzLmZhY3RvcihxdWFudGl0aWVzKSwgeSA9IGZyZXF1ZW5jeSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJza3libHVlIikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBmcmVxdWVuY3kpLCB2anVzdCA9IC0wLjMsIHNpemUgPSAzLjUpICsKICBsYWJzKHggPSAiUXVhbnRpdGllcyIsIHkgPSAiRnJlcXVlbmN5IiwgdGl0bGUgPSAiSGlzdG9ncmFtIG9mIFF1YW50aXRpZXMgKFBhcnQgNCkiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQoKcGxvdDUgPC0gZ2dwbG90KGRmX3F1YW50aXRpZXNfcGFydDUsIGFlcyh4ID0gYXMuZmFjdG9yKHF1YW50aXRpZXMpLCB5ID0gZnJlcXVlbmN5KSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gInNreWJsdWUiKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGZyZXF1ZW5jeSksIHZqdXN0ID0gLTAuMywgc2l6ZSA9IDMuNSkgKwogIGxhYnMoeCA9ICJRdWFudGl0aWVzIiwgeSA9ICJGcmVxdWVuY3kiLCB0aXRsZSA9ICJIaXN0b2dyYW0gb2YgUXVhbnRpdGllcyAoUGFydCA1KSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCgpwbG90NiA8LSBnZ3Bsb3QoZGZfcXVhbnRpdGllc19wYXJ0NiwgYWVzKHggPSBhcy5mYWN0b3IocXVhbnRpdGllcyksIHkgPSBmcmVxdWVuY3kpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAic2t5Ymx1ZSIpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gZnJlcXVlbmN5KSwgdmp1c3QgPSAtMC4zLCBzaXplID0gMy41KSArCiAgbGFicyh4ID0gIlF1YW50aXRpZXMiLCB5ID0gIkZyZXF1ZW5jeSIsIHRpdGxlID0gIkhpc3RvZ3JhbSBvZiBRdWFudGl0aWVzIChQYXJ0IDYpIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKCnBsb3Q3IDwtIGdncGxvdChkZl9xdWFudGl0aWVzX3BhcnQ3LCBhZXMoeCA9IGFzLmZhY3RvcihxdWFudGl0aWVzKSwgeSA9IGZyZXF1ZW5jeSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJza3libHVlIikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBmcmVxdWVuY3kpLCB2anVzdCA9IC0wLjMsIHNpemUgPSAzLjUpICsKICBsYWJzKHggPSAiUXVhbnRpdGllcyIsIHkgPSAiRnJlcXVlbmN5IiwgdGl0bGUgPSAiSGlzdG9ncmFtIG9mIFF1YW50aXRpZXMgKFBhcnQgNykiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQoKcGxvdDggPC0gZ2dwbG90KGRmX3F1YW50aXRpZXNfcGFydDgsIGFlcyh4ID0gYXMuZmFjdG9yKHF1YW50aXRpZXMpLCB5ID0gZnJlcXVlbmN5KSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gInNreWJsdWUiKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGZyZXF1ZW5jeSksIHZqdXN0ID0gLTAuMywgc2l6ZSA9IDMuNSkgKwogIGxhYnMoeCA9ICJRdWFudGl0aWVzIiwgeSA9ICJGcmVxdWVuY3kiLCB0aXRsZSA9ICJIaXN0b2dyYW0gb2YgUXVhbnRpdGllcyAoUGFydCA4KSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCgpwcmludChwbG90MSkKcHJpbnQocGxvdDIpCnByaW50KHBsb3QzKQpwcmludChwbG90NCkKcHJpbnQocGxvdDUpCnByaW50KHBsb3Q2KQpwcmludChwbG90NykKcHJpbnQocGxvdDgpCmBgYAojIyBTdW1tYXJpemUgYnVwcmVub3JwaGluZSBwcmVzY3JpcHRpb25zIGJ5IHllYXIKYGBge3J9CnByZXNjcmlwdGlvbnNfYnlfeWVhciA8LSBjbGFpbXNfZGVtbyAlPiUKICBncm91cF9ieSh5ZWFyKSAlPiUKICBzdW1tYXJpc2UoY291bnQgPSBuKCkpCgojMS4gQmFyIEdyYXBoIG9mIENvdW50cyBieSBZZWFyCiMgUGxvdCB0aGUgYmFyIGdyYXBoCmdncGxvdChwcmVzY3JpcHRpb25zX2J5X3llYXIsIGFlcyh4ID0geWVhciwgeSA9IGNvdW50KSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgbGFicyh0aXRsZSA9ICJOdW1iZXIgb2YgUHJlc2NyaXB0aW9ucyBieSBZZWFyIiwKICAgICAgIHggPSAiWWVhciIsCiAgICAgICB5ID0gIk51bWJlciBvZiBQcmVzY3JpcHRpb25zIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKYGBgCkZyb20gMjAwNiB0byAyMDEzLCB0aGVyZSB3YXMgYSBzdGVhZHkgaW5jcmVhc2UgaW4gdGhlIG51bWJlciBvZiBwcmVzY3JpcHRpb25zLCBwZWFraW5nIGluIDIwMTMgYW5kIDIwMTQgd2l0aCBvdmVyIDMwMCwwMDAgcHJlc2NyaXB0aW9ucyBlYWNoIHllYXIuIAoKVGhpcyByaXNlIHN1Z2dlc3RzIGEgZ3Jvd2luZyB0cmVuZCBpbiBwcmVzY3JpcHRpb24gcmF0ZXMgb3IgaW1wcm92ZWQgYWNjZXNzIHRvIGhlYWx0aGNhcmUgZHVyaW5nIHRoZXNlIHllYXJzLiAKCkhvd2V2ZXIsIGZvbGxvd2luZyAyMDE0LCB0aGVyZSBpcyBhIG5vdGFibGUgZGVjbGluZSBpbiB0aGUgbnVtYmVyIG9mIHByZXNjcmlwdGlvbnMsIHJlYWNoaW5nIGl0cyBsb3dlc3QgcG9pbnQgYXJvdW5kIDIwMTkuIFRoaXMgZGVjbGluZSBtYXkgYmUgYXR0cmlidXRlZCB0byBjaGFuZ2VzIGluIGhlYWx0aGNhcmUgcG9saWNpZXMuIAoKSW4gdGhlIHN1YnNlcXVlbnQgeWVhcnMsIHRoZXJlIGlzIGEgc2xpZ2h0IHJlY292ZXJ5IGluIDIwMjEgYW5kIDIwMjIsIGluZGljYXRpbmcgYSByZXN1cmdlbmNlIGluIHByZXNjcmlwdGlvbiByYXRlcywgYnV0IHRoaXMgaXMgZm9sbG93ZWQgYnkgYSBzaGFycCBkZWNyZWFzZSBpbiAyMDIzLiBUaGlzIGNvdWxkIGJlIGluZmx1ZW5jZWQgYnkgZXh0ZXJuYWwgZmFjdG9ycyBzdWNoIGFzIGNoYW5nZXMgaW4gaGVhbHRoY2FyZSByZWd1bGF0aW9ucywgZWNvbm9taWMgY29uZGl0aW9ucywgb3IgdGhlIGltcGFjdCBvZiBnbG9iYWwgZXZlbnRzIGxpa2UgdGhlIENPVklELTE5IHBhbmRlbWljLiAKCgojIyBTdW1tYXJpemUgYnVwcmVub3JwaGluZSBwcmVzY3JpcHRpb25zIGJ5IHllYXIsIFN0cmF0aWZpZWQgYnkgU2V4IAoKRmlsdGVyIHRoZSBkYXRhIHRvIGluY2x1ZGUgb25seSBlbnRyaWVzIHdpdGggc2V4ICJGIiBhbmQgIk0iCmBgYHtyfQpmaWcxX2ZpbHRlcmVkIDwtIGNsYWltc19kZW1vICU+JQogIGZpbHRlcihkZXJfc2V4ICVpbiUgYygiRiIsICJNIikpCgpwcmVzY3JpcHRpb25zX2J5X3llYXJfc2V4IDwtIGZpZzFfZmlsdGVyZWQgJT4lCiAgZ3JvdXBfYnkoeWVhciwgZGVyX3NleCkgJT4lCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKQoKZ2dwbG90KHByZXNjcmlwdGlvbnNfYnlfeWVhcl9zZXgsIGFlcyh4ID0geWVhciwgeSA9IGNvdW50LCBmaWxsID0gZGVyX3NleCkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiKSArCiAgbGFicyh0aXRsZSA9ICJOdW1iZXIgb2YgUHJlc2NyaXB0aW9ucyBieSBZZWFyLCBTdHJhdGlmaWVkIGJ5IFNleCIsCiAgICAgICB4ID0gIlllYXIiLAogICAgICAgeSA9ICJOdW1iZXIgb2YgUHJlc2NyaXB0aW9ucyIsCiAgICAgICBmaWxsID0gIlNleCIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCmBgYApUaGUgc2Vjb25kIGJhciBncmFwaCBzaG93cyB0aGUgbnVtYmVyIG9mIHByZXNjcmlwdGlvbnMgYnkgeWVhciwgc3RyYXRpZmllZCBieSBzZXggKEYgYW5kIE0pLiBJdCBoaWdobGlnaHRzIHNldmVyYWwgaW1wb3J0YW50IHRyZW5kcyBhbmQgZGlmZmVyZW5jZXMgYmV0d2VlbiBtYWxlIGFuZCBmZW1hbGUgcHJlc2NyaXB0aW9uIHJhdGVzLiBPdmVyYWxsLCB0aGUgbnVtYmVyIG9mIHByZXNjcmlwdGlvbnMgZm9yIGJvdGggc2V4ZXMgZm9sbG93cyBhIHNpbWlsYXIgcGF0dGVybiwgd2l0aCBhbiBpbmNyZWFzZSBmcm9tIDIwMDYsIHBlYWtpbmcgYXJvdW5kIDIwMTMgYW5kIDIwMTQsIGZvbGxvd2VkIGJ5IGEgZGVjbGluZS4gCgpUaHJvdWdob3V0IHRoZSB5ZWFycywgbWFsZXMgY29uc2lzdGVudGx5IGhhdmUgaGlnaGVyIHByZXNjcmlwdGlvbiBjb3VudHMgY29tcGFyZWQgdG8gZmVtYWxlcy4gVGhlIHBlYWsgeWVhcnMgb2YgMjAxMyBhbmQgMjAxNCBzaG93IHRoZSBtb3N0IHNpZ25pZmljYW50IGRpZmZlcmVuY2VzLCB3aXRoIG1hbGVzIGhhdmluZyBzdWJzdGFudGlhbGx5IG1vcmUgcHJlc2NyaXB0aW9ucyB0aGFuIGZlbWFsZXMuIEFmdGVyIDIwMTQsIHRoZSBudW1iZXIgb2YgcHJlc2NyaXB0aW9ucyBmb3IgYm90aCBzZXhlcyBkZWNsaW5lcywgcmVhY2hpbmcgYSBsb3cgcG9pbnQgYXJvdW5kIDIwMTkuIAoKVGhpcyBncmFwaCBpbmRpY2F0ZXMgdGhhdCB3aGlsZSB0aGUgb3ZlcmFsbCBwcmVzY3JpcHRpb24gdHJlbmRzIGFyZSBzaW1pbGFyIGZvciBib3RoIG1hbGVzIGFuZCBmZW1hbGVzLCBtYWxlcyBjb25zaXN0ZW50bHkgcmVjZWl2ZSBtb3JlIHByZXNjcmlwdGlvbnMgdGhhbiBmZW1hbGVzIGFjcm9zcyBhbGwgeWVhcnMuIAoKY3JlYXRlIGEgbWFwIG9mIHByZXNjcmlwdGlvbnMgYnkgVVMgc3RhdGUgCgpgYGB7cn0KZmlnMjwtY2xhaW1zX2RlbW8gJT4lIHNlbGVjdChwYXRfc3RhdGUsIHllYXIpIAp3cml0ZS5jc3YoZmlnMiwgImZpZzIuY3N2IikgIAoKcHJlc2NyaXB0aW9uc19ieV9zdGF0ZSA8LSBmaWcyICU+JQogIGdyb3VwX2J5KHBhdF9zdGF0ZSkgJT4lCiAgc3VtbWFyaXNlKHRvdGFsX3ByZXNjcmlwdGlvbnMgPSBuKCkpCgpoZWFkKHByZXNjcmlwdGlvbnNfYnlfc3RhdGUpCnByZXNjcmlwdGlvbnNfYnlfc3RhdGUgPC0gYXMuZGF0YS5mcmFtZShwcmVzY3JpcHRpb25zX2J5X3N0YXRlKQpwcmVzY3JpcHRpb25zX2J5X3N0YXRlPC1wcmVzY3JpcHRpb25zX2J5X3N0YXRlWy0xLF0KY29sbmFtZXMocHJlc2NyaXB0aW9uc19ieV9zdGF0ZSlbMV08LSJzdGF0ZSIKCnBsb3RfdXNtYXAoZGF0YSA9IHByZXNjcmlwdGlvbnNfYnlfc3RhdGUsIHZhbHVlcyA9ICJ0b3RhbF9wcmVzY3JpcHRpb25zIiwgY29sb3IgPSAid2hpdGUiKSArCiAgc2NhbGVfZmlsbF9jb250aW51b3VzKG5hbWUgPSAiVG90YWwgUHJlc2NyaXB0aW9ucyIsIGxhYmVsID0gc2NhbGVzOjpjb21tYSkgKwogIGxhYnModGl0bGUgPSAiVG90YWwgTnVtYmVyIG9mIFByZXNjcmlwdGlvbnMgYnkgVVMgU3RhdGUiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikKYGBgCgojIyBjcmVhdGUgYSBtYXAgb2YgVG90YWwgUHJlc2NyaXB0aW9ucyBieSBVUyBTdGF0ZQpgYGB7cn0Kc3RhdGVfZGF0YSA8LSBtZXJnZShwcmVzY3JpcHRpb25zX2J5X3N0YXRlLCBzdGF0ZV9jZW50ZXJzLCBieS54ID0gInN0YXRlIiwgYnkueSA9ICJzdGF0ZSIpCgp0b3RhbF9wcmVzY3JpcHRpb25zX3Bsb3QgPC0gcGxvdF91c21hcChkYXRhID0gcHJlc2NyaXB0aW9uc19ieV9zdGF0ZSwgdmFsdWVzID0gInRvdGFsX3ByZXNjcmlwdGlvbnMiLCBjb2xvciA9ICJ3aGl0ZSIpICsKICBnZW9tX3RleHQoZGF0YSA9IHN0YXRlX2RhdGEsIGFlcyh4ID0geCwgeSA9IHksIGxhYmVsID0gc3RhdGUpLCBzaXplID0gMywgaGp1c3QgPSAwLjUsIGNvbG9yID0gImJsYWNrIikgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKG5hbWUgPSAiVG90YWwgUHJlc2NyaXB0aW9ucyIsIGNvbG9ycyA9IGMoImJsdWUiLCAiZ3JlZW4iLCAieWVsbG93IiwgInJlZCIpLCBsYWJlbHMgPSBzY2FsZXM6OmNvbW1hLCAKICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoMCwgbWF4KHByZXNjcmlwdGlvbnNfYnlfc3RhdGUkdG90YWxfcHJlc2NyaXB0aW9ucyksIGxlbmd0aC5vdXQgPSA2KSkgKwogIGxhYnModGl0bGUgPSAiVG90YWwgTnVtYmVyIG9mIFByZXNjcmlwdGlvbnMgYnkgVVMgU3RhdGUiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikKCmdncGxvdGx5KHRvdGFsX3ByZXNjcmlwdGlvbnNfcGxvdCkKYGBgCiMjIENyZWF0ZSBhIFNoaW55IEFwcCAKYGBge3J9CnVpIDwtIGZsdWlkUGFnZSgKICB0aXRsZVBhbmVsKCJOdW1iZXIgb2YgUHJlc2NyaXB0aW9ucyBieSBVUyBTdGF0ZSIpLAogIHRhYnNldFBhbmVsKAogICAgdGFiUGFuZWwoIlRvdGFsIiwKICAgICAgICAgICAgIHBsb3RPdXRwdXQoInN0YXRpY01hcCIpCiAgICApLAogICAgdGFiUGFuZWwoIlllYXJseSIsCiAgICAgICAgICAgICBzaWRlYmFyTGF5b3V0KAogICAgICAgICAgICAgICBzaWRlYmFyUGFuZWwoCiAgICAgICAgICAgICAgICAgc2VsZWN0SW5wdXQoInllYXIiLCAiU2VsZWN0IFllYXI6IiwgY2hvaWNlcyA9IHVuaXF1ZShwcmVzY3JpcHRpb25zX2J5X3N0YXRlX3llYXIkeWVhcikpCiAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgIG1haW5QYW5lbCgKICAgICAgICAgICAgICAgICBwbG90bHlPdXRwdXQoInVzTWFwIikKICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgKQogICAgKSwKICAgIHRhYlBhbmVsKCJQcm9kdWN0IFRyZW5kcyIsCiAgICAgICAgICAgICBwbG90T3V0cHV0KCJwcm9kdWN0VHJlbmRHcmFwaCIpCiAgICApCiAgKQopCgpzZXJ2ZXIgPC0gZnVuY3Rpb24oaW5wdXQsIG91dHB1dCkgewogIG91dHB1dCRzdGF0aWNNYXAgPC0gcmVuZGVyUGxvdCh7CiAgICBzdGF0ZV9kYXRhIDwtIG1lcmdlKHByZXNjcmlwdGlvbnNfYnlfc3RhdGUsIHN0YXRlX2NlbnRlcnMsIGJ5LnggPSAic3RhdGUiLCBieS55ID0gInN0YXRlIikKICAgIAogICAgcGxvdF91c21hcChkYXRhID0gcHJlc2NyaXB0aW9uc19ieV9zdGF0ZSwgdmFsdWVzID0gInRvdGFsX3ByZXNjcmlwdGlvbnMiLCBjb2xvciA9ICJ3aGl0ZSIpICsKICAgICAgZ2VvbV90ZXh0KGRhdGEgPSBzdGF0ZV9kYXRhLCBhZXMoeCA9IHgsIHkgPSB5LCBsYWJlbCA9IHN0YXRlKSwgc2l6ZSA9IDMsIGhqdXN0ID0gMC41LCBjb2xvciA9ICJibGFjayIpICsKICAgICAgc2NhbGVfZmlsbF9ncmFkaWVudG4obmFtZSA9ICJUb3RhbCBQcmVzY3JpcHRpb25zIiwgY29sb3JzID0gYygiYmx1ZSIsICJncmVlbiIsICJ5ZWxsb3ciLCAicmVkIiksIGxhYmVscyA9IHNjYWxlczo6Y29tbWEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoMCwgbWF4KHByZXNjcmlwdGlvbnNfYnlfc3RhdGUkdG90YWxfcHJlc2NyaXB0aW9ucyksIGxlbmd0aC5vdXQgPSA2KSkgKwogICAgICBsYWJzKHRpdGxlID0gIlRvdGFsIE51bWJlciBvZiBQcmVzY3JpcHRpb25zIGJ5IFVTIFN0YXRlIikgKwogICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKQogIH0pCiAgCiAgb3V0cHV0JHVzTWFwIDwtIHJlbmRlclBsb3RseSh7CiAgICBkYXRhX3llYXIgPC0gcHJlc2NyaXB0aW9uc19ieV9zdGF0ZV95ZWFyICU+JQogICAgICBmaWx0ZXIoeWVhciA9PSBpbnB1dCR5ZWFyKQogICAgCiAgICBzdGF0ZV9kYXRhX3llYXIgPC0gbWVyZ2UoZGF0YV95ZWFyLCBzdGF0ZV9jZW50ZXJzLCBieSA9ICJzdGF0ZSIpCiAgICAKICAgIHAgPC0gcGxvdF91c21hcChkYXRhID0gZGF0YV95ZWFyLCB2YWx1ZXMgPSAidG90YWxfcHJlc2NyaXB0aW9ucyIsIGNvbG9yID0gIndoaXRlIikgKwogICAgICBnZW9tX3RleHQoZGF0YSA9IHN0YXRlX2RhdGFfeWVhciwgYWVzKHggPSB4LCB5ID0geSwgbGFiZWwgPSBzdGF0ZSksIHNpemUgPSAzLCBoanVzdCA9IDAuNSwgY29sb3IgPSAiYmxhY2siKSArCiAgICAgIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKG5hbWUgPSBwYXN0ZSgiUHJlc2NyaXB0aW9ucyBpbiIsIGlucHV0JHllYXIpLCBjb2xvcnMgPSBjKCJibHVlIiwgImdyZWVuIiwgInllbGxvdyIsICJyZWQiKSwgbGFiZWxzID0gc2NhbGVzOjpjb21tYSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgwLCBtYXgoZGF0YV95ZWFyJHRvdGFsX3ByZXNjcmlwdGlvbnMpLCBsZW5ndGgub3V0ID0gNikpICsKICAgICAgbGFicyh0aXRsZSA9IHBhc3RlKCJOdW1iZXIgb2YgQnVwcmVub3JwaGluZSBPVUQgUHJlc2NyaXB0aW9ucyBieSBVUyBTdGF0ZSBpbiIsIGlucHV0JHllYXIpKSArCiAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpCiAgICAKICAgIGdncGxvdGx5KHApCiAgfSkKICAKICBvdXRwdXQkcHJvZHVjdFRyZW5kR3JhcGggPC0gcmVuZGVyUGxvdCh7CiAgICBnZ3Bsb3QocHJvZHVjdF9kYXRhLCBhZXMoeCA9IHllYXIsIHkgPSBwZXJjZW50YWdlLCBjb2xvciA9IHByb2R1Y3RfbmFtZSkpICsKICAgICAgZ2VvbV9saW5lKHNpemUgPSAxLjIpICsKICAgICAgc2NhbGVfY29sb3JfdmlyaWRpcyhkaXNjcmV0ZSA9IFRSVUUpICsgCiAgICAgIGxhYnModGl0bGUgPSAiUGVyY2VudGFnZSBvZiBFYWNoIFByb2R1Y3QgT3ZlciBUaW1lICgyMDA2LTIwMjMpIiwKICAgICAgICAgICB4ID0gIlllYXIiLAogICAgICAgICAgIHkgPSAiUGVyY2VudGFnZSBvZiBUb3RhbCBQcmVzY3JpcHRpb25zIiwKICAgICAgICAgICBjb2xvciA9ICJQcm9kdWN0IikgKwogICAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpKQogIH0pCn0KCnNoaW55QXBwKHVpID0gdWksIHNlcnZlciA9IHNlcnZlcikKYGBgCgojIyBDcmVhdGUgYSB0ZW1wb3JhbCBncmFwaCBvZiBQcm9kdWN0IHRyZW5kcyBPdmVyIFRpbWUKCmBgYHtyfQpwcm9kdWN0X3RyZW5kX3Bsb3QgPC0gZ2dwbG90KHByb2R1Y3RfZGF0YSwgYWVzKHggPSB5ZWFyLCB5ID0gcGVyY2VudGFnZSwgY29sb3IgPSBwcm9kdWN0X25hbWUpKSArCiAgZ2VvbV9saW5lKHNpemUgPSAxLjIpICsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQzIikgKyAKICBsYWJzKHRpdGxlID0gIlBlcmNlbnRhZ2Ugb2YgRWFjaCBQcm9kdWN0IE92ZXIgVGltZSAoMjAwNi0yMDIzKSIsCiAgICAgICB4ID0gIlllYXIiLAogICAgICAgeSA9ICJQZXJjZW50YWdlIG9mIFRvdGFsIFByZXNjcmlwdGlvbnMiLAogICAgICAgY29sb3IgPSAiUHJvZHVjdCIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSkKCmdncGxvdGx5KHByb2R1Y3RfdHJlbmRfcGxvdCkKYGBgCjI0MDkyMyowLjU3MgojIyBkaXNjdXNzaW9uIG9mIHByb2R1Y3QgVHJlbmRzIAoyNDA5MjMtMTM3ODA4CjEwMC01Ny4yCjg2NjkwNC8yNDA5MjMKClNVQk9YT05FIApUcmVuZDogVGhlcmUgaXMgYSBzaWduaWZpY2FudCBpbmNyZWFzZSBpbiB0aGUgcGVyY2VudGFnZSBvZiBTVUJPWE9ORSBwcmVzY3JpcHRpb25zIHN0YXJ0aW5nIGFyb3VuZCAyMDEwLCByZWFjaGluZyBhIHBlYWsgYXJvdW5kIDIwMTUtMjAxNiwgZm9sbG93ZWQgYnkgYSBzaGFycCBkZWNsaW5lLgoKTGl0ZXJhdHVyZSBTdXBwb3J0OiBTVUJPWE9ORSwgYSBjb21iaW5hdGlvbiBvZiBidXByZW5vcnBoaW5lIGFuZCBuYWxveG9uZSwgd2FzIGFwcHJvdmVkIGJ5IHRoZSBGREEgaW4gMjAwMiBmb3IgdGhlIHRyZWF0bWVudCBvZiBvcGlvaWQgZGVwZW5kZW5jZS4gVGhlIGluY3JlYXNlIGluIGl0cyBwcmVzY3JpcHRpb24gYWxpZ25zIHdpdGggaXRzIGVmZmVjdGl2ZW5lc3MgaW4gdHJlYXRpbmcgb3Bpb2lkIHVzZSBkaXNvcmRlciAoT1VEKSBhbmQgaXRzIGV4cGFuZGVkIHVzZSBpbiBjbGluaWNhbCBwcmFjdGljZS4gVGhlIGRlY2xpbmUgaW4gcmVjZW50IHllYXJzIGNvdWxkIGJlIGF0dHJpYnV0ZWQgdG8gdGhlIGludHJvZHVjdGlvbiBvZiBuZXcgYnVwcmVub3JwaGluZSBwcm9kdWN0cyBhbmQgdGhlIGltcGxlbWVudGF0aW9uIG9mIGdlbmVyaWMgdmVyc2lvbnMsIHdoaWNoIHRlbmQgdG8gYmUgbGVzcyBleHBlbnNpdmUgYW5kIG1vcmUgYWNjZXNzaWJsZS4KCkJVUFJFTk9SUEhJTkUgSENMClRyZW5kOiBTaG93cyBhIHNpZ25pZmljYW50IGluY3JlYXNlIHN0YXJ0aW5nIGFyb3VuZCAyMDE4LiAKTGl0ZXJhdHVyZSBTdXBwb3J0OiBCdXByZW5vcnBoaW5lIEhDTCBoYXMgYmVlbiB1c2VkIGZvciBib3RoIHBhaW4gbWFuYWdlbWVudCBhbmQgT1VELiBUaGUgaW5jcmVhc2UgaW4gcmVjZW50IHllYXJzIGNhbiBiZSBhdHRyaWJ1dGVkIHRvIHRoZSBicm9hZGVyIGFjY2VwdGFuY2UgYW5kIHVuZGVyc3RhbmRpbmcgb2YgYnVwcmVub3JwaGluZSdzIGVmZmljYWN5IGluIHRyZWF0aW5nIE9VRC4gSXQgbWF5IGFsc28gcmVmbGVjdCB0aGUgRkRBJ3MgZWZmb3J0cyB0byBleHBhbmQgYWNjZXNzIHRvIGJ1cHJlbm9ycGhpbmUgYXMgcGFydCBvZiB0aGUgcmVzcG9uc2UgdG8gdGhlIG9waW9pZCBjcmlzaXMuCgpCVVBSRU5PUlBISU5FIEhDTC9OQUxPWE9ORQpUcmVuZDogU3RlYWR5IGluY3JlYXNlIGluIHBlcmNlbnRhZ2Ugb3ZlciB0aW1lIGFmdGVyIDIwMTMuIApMaXRlcmF0dXJlIFN1cHBvcnQ6IFRoaXMgdHJlbmQgc3VwcG9ydHMgdGhlIGxpdGVyYXR1cmUgdGhhdCBlbXBoYXNpemVzIHRoZSBlZmZlY3RpdmVuZXNzIG9mIGNvbWJpbmF0aW9uIHRoZXJhcGllcyAoYnVwcmVub3JwaGluZS9uYWxveG9uZSkgaW4gcmVkdWNpbmcgdGhlIHBvdGVudGlhbCBmb3IgbWlzdXNlIGNvbXBhcmVkIHRvIGJ1cHJlbm9ycGhpbmUgYWxvbmUuIFRoZSBpbmNyZWFzZSBpbiBwcmVzY3JpcHRpb25zIGFsc28gY29pbmNpZGVzIHdpdGggdGhlIEZEQSdzIGVuY291cmFnZW1lbnQgb2Ygc3VjaCBjb21iaW5hdGlvbnMgZm9yIHNhZmV0eSByZWFzb25zLgoKU1VCVVRFWApUcmVuZDogSGlnaCBwZXJjZW50YWdlIGluaXRpYWxseSwgZm9sbG93ZWQgYnkgYSBkZWNsaW5lIGFyb3VuZCAyMDEwIGFuZCByZW1haW5pbmcgbG93IHRoZXJlYWZ0ZXIuCkxpdGVyYXR1cmUgU3VwcG9ydDogU1VCVVRFWCwgd2hpY2ggY29udGFpbnMgb25seSBidXByZW5vcnBoaW5lLCB3YXMgY29tbW9ubHkgdXNlZCBiZWZvcmUgdGhlIGludHJvZHVjdGlvbiBvZiBjb21iaW5hdGlvbiBwcm9kdWN0cy4gSXRzIGRlY2xpbmUgaXMgc3VwcG9ydGVkIGJ5IEZEQSByZWNvbW1lbmRhdGlvbnMgZmF2b3JpbmcgY29tYmluYXRpb24gcHJvZHVjdHMgbGlrZSBTVUJPWE9ORSB0byByZWR1Y2UgbWlzdXNlIHBvdGVudGlhbC4KClNVQkxPQ0FERQpUcmVuZDogRW1lcmdlcyBhcm91bmQgMjAxOCB3aXRoIGEgcmlzaW5nIHRyZW5kLgpMaXRlcmF0dXJlIFN1cHBvcnQ6IFNVQkxPQ0FERSwgYW4gZXh0ZW5kZWQtcmVsZWFzZSBpbmplY3RhYmxlIGZvcm0gb2YgYnVwcmVub3JwaGluZSwgd2FzIGFwcHJvdmVkIGJ5IHRoZSBGREEgaW4gMjAxNy4gSXRzIGluY3JlYXNpbmcgcHJlc2NyaXB0aW9uIHJhdGUgcmVmbGVjdHMgdGhlIGdyb3dpbmcgYWNjZXB0YW5jZSBhbmQgdXRpbGl6YXRpb24gb2YgbG9uZy1hY3RpbmcgZm9ybXVsYXRpb25zIGZvciBiZXR0ZXIgY29tcGxpYW5jZSBhbmQgc3VzdGFpbmVkIHJlY292ZXJ5IGluIE9VRCB0cmVhdG1lbnQuCgpQUk9CVVBISU5FIElNUExBTlQgS0lUClRyZW5kOiBTaG93cyBhIHZlcnkgbG93IGFuZCByZWxhdGl2ZWx5IGZsYXQgdHJlbmQuCkxpdGVyYXR1cmUgU3VwcG9ydDogUFJPQlVQSElORSwgYXBwcm92ZWQgaW4gMjAxNiwgaXMgYW4gaW1wbGFudGFibGUgZm9ybSBvZiBidXByZW5vcnBoaW5lIGRlc2lnbmVkIHRvIHByb3ZpZGUgY29udGludW91cyBkZWxpdmVyeSBvdmVyIHNpeCBtb250aHMuIEl0cyBsaW1pdGVkIHVzZSBtaWdodCBiZSBkdWUgdG8gdGhlIGludmFzaXZlIG5hdHVyZSBvZiBpbXBsYW50YXRpb24gYW5kIHRoZSBwcmVmZXJlbmNlIGZvciBsZXNzIGludmFzaXZlIGFkbWluaXN0cmF0aW9uIHJvdXRlcy4KClpVQlNPTFYKVHJlbmQ6IFNob3dzIGEgbWlub3IgcHJlc2VuY2Ugd2l0aCBzb21lIGluY3JlYXNlIG92ZXIgdGltZS4KTGl0ZXJhdHVyZSBTdXBwb3J0OiBaVUJTT0xWIGlzIGFub3RoZXIgYnVwcmVub3JwaGluZS9uYWxveG9uZSBjb21iaW5hdGlvbiBwcm9kdWN0IHdpdGggYSBkaWZmZXJlbnQgZm9ybXVsYXRpb24gYW5kIGJpb2F2YWlsYWJpbGl0eS4gSXRzIGludHJvZHVjdGlvbiBwcm92aWRlZCBhbiBhbHRlcm5hdGl2ZSB0byBTVUJPWE9ORSwgYW5kIEkgYmVsaWV2ZSBpcyBoaWdobHkgcmVsaWFudCBvbiBwcmVzY3JpYmVyIGhhYml0cy4gCgpCVU5BVkFJTApUcmVuZDogTWlub3IgcHJlc2VuY2Ugd2l0aCBzbGlnaHQgZmx1Y3R1YXRpb24uCkxpdGVyYXR1cmUgU3VwcG9ydDogQlVOQVZBSUwsIGEgYnVjY2FsIGZpbG0gZm9ybXVsYXRpb24gb2YgYnVwcmVub3JwaGluZS9uYWxveG9uZSwgd2FzIGludHJvZHVjZWQgYXMgYW4gYWx0ZXJuYXRpdmUgdG8gc3VibGluZ3VhbCBmb3JtdWxhdGlvbnMuIEl0cyByZWxhdGl2ZWx5IG1pbm9yIHVwdGFrZSBjb3VsZCBiZSBkdWUgdG8gY29tcGV0aXRpb24gd2l0aCBvdGhlciBlc3RhYmxpc2hlZCBjb21iaW5hdGlvbiBwcm9kdWN0cy4KClRyZW5kcyBOb3QgRnVsbHkgU3VwcG9ydGVkIGJ5IExpdGVyYXR1cmUKClNoYXJwIERlY2xpbmUgaW4gU1VCT1hPTkU6IFRoZSByYXBpZCBkZWNsaW5lIGluIFNVQk9YT05FIHByZXNjcmlwdGlvbnMgcG9zdC0yMDE1IGlzIHNoYXJwZXIgdGhhbiBtaWdodCBiZSBleHBlY3RlZCBzb2xlbHkgZHVlIHRvIHRoZSBpbnRyb2R1Y3Rpb24gb2YgZ2VuZXJpY3MgYW5kIG5ldyBmb3JtdWxhdGlvbnMuIFRoaXMgY291bGQgaW5kaWNhdGUgb3RoZXIgZmFjdG9ycyBhdCBwbGF5LCBzdWNoIGFzIGNoYW5nZXMgaW4gaW5zdXJhbmNlIGNvdmVyYWdlLCBwcmVzY3JpYmVyIHByZWZlcmVuY2VzLCBvciByZWd1bGF0b3J5IGFjdGlvbnMgdGFyZ2V0aW5nIHNwZWNpZmljIHByb2R1Y3RzLgoKUmVsYXRpdmVseSBGbGF0IFRyZW5kIGZvciBQUk9CVVBISU5FOiBEZXNwaXRlIGl0cyBpbm5vdmF0aXZlIGltcGxhbnQgYXBwcm9hY2gsIFBST0JVUEhJTkXigJlzIGxpbWl0ZWQgYWRvcHRpb24gbWlnaHQgbm90IGZ1bGx5IGFsaWduIHdpdGggaXRzIHBvdGVudGlhbCBiZW5lZml0cyBhcyBoaWdobGlnaHRlZCBpbiBjbGluaWNhbCBzdHVkaWVzLiBGYWN0b3JzIHN1Y2ggYXMgY29zdCwgcGF0aWVudCBhbmQgcHJvdmlkZXIgYWNjZXB0YW5jZSwgYW5kIHByb2NlZHVyYWwgY29tcGxleGl0eSBsaWtlbHkgcGxheSBhIHJvbGUuCgojIyBzdW1tYXJpemluZyB0aGUgZmluYWwgY29ob3J0IGRhdGFzZXQgCgpgYGB7cn0KcmVjdHlwZV9zdW1tYXJ5IDwtIHN1bW1hcnkoY2xhaW1zX2RlbW8kcmVjdHlwZSkKZG9zYWdlX2Zvcm1fbm1fc3VtbWFyeSA8LSBzdW1tYXJ5KGNsYWltc19kZW1vJGRvc2FnZV9mb3JtX25tKQpyb3V0ZV9zdW1tYXJ5IDwtIHN1bW1hcnkoY2xhaW1zX2RlbW8kcm91dGUpCnN0cmVuZ3RoX3N1bW1hcnkgPC0gc3VtbWFyeShjbGFpbXNfZGVtbyRzdHJlbmd0aCkKCnJlY3R5cGVfcGxvdCA8LSBnZ3Bsb3QoY2xhaW1zX2RlbW8sIGFlcyh4ID0gZmFjdG9yKHJlY3R5cGUpKSkgKwogIGdlb21fYmFyKGZpbGwgPSAnc2t5Ymx1ZScsIGNvbG9yID0gJ2JsYWNrJykgKwogIGxhYnModGl0bGUgPSAnRGlzdHJpYnV0aW9uIG9mIFJlY3R5cGUnLCB4ID0gJ1JlY3R5cGUnLCB5ID0gJ0ZyZXF1ZW5jeScpICsKICB0aGVtZV9taW5pbWFsKCkKCmRvc2FnZV9mb3JtX25tX3Bsb3QgPC0gZ2dwbG90KGNsYWltc19kZW1vLCBhZXMoeCA9IGZhY3Rvcihkb3NhZ2VfZm9ybV9ubSkpKSArCiAgZ2VvbV9iYXIoZmlsbCA9ICdzYWxtb24nLCBjb2xvciA9ICdibGFjaycpICsKICBsYWJzKHRpdGxlID0gJ0Rpc3RyaWJ1dGlvbiBvZiBEb3NhZ2UgRm9ybSBOYW1lJywgeCA9ICdEb3NhZ2UgRm9ybSBOYW1lJywgeSA9ICdGcmVxdWVuY3knKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQoKCnJvdXRlX3Bsb3QgPC0gZ2dwbG90KGNsYWltc19kZW1vLCBhZXMoeCA9IGZhY3Rvcihyb3V0ZSkpKSArCiAgZ2VvbV9iYXIoZmlsbCA9ICdsaWdodGdyZWVuJywgY29sb3IgPSAnYmxhY2snKSArCiAgbGFicyh0aXRsZSA9ICdEaXN0cmlidXRpb24gb2YgUm91dGUnLCB4ID0gJ1JvdXRlJywgeSA9ICdGcmVxdWVuY3knKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQoKCnN0cmVuZ3RoX3Bsb3QgPC0gZ2dwbG90KGNsYWltc19kZW1vLCBhZXMoeCA9IGZhY3RvcihzdHJlbmd0aCkpKSArCiAgZ2VvbV9iYXIoZmlsbCA9ICdsaWdodGJsdWUnLCBjb2xvciA9ICdibGFjaycpICsKICBsYWJzKHRpdGxlID0gJ0Rpc3RyaWJ1dGlvbiBvZiBTdHJlbmd0aCcsIHggPSAnU3RyZW5ndGgnLCB5ID0gJ0ZyZXF1ZW5jeScpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCgpyZWN0eXBlX3Bsb3QgCmRvc2FnZV9mb3JtX25tX3Bsb3QgCnJvdXRlX3Bsb3QgCnN0cmVuZ3RoX3Bsb3QgCmBgYApjb2xuYW1lcyhjbGFpbXNfZGVtbykgCgpgYGB7cn0Kc2VsZWN0ZWRfZGF0YSA8LSBjbGFpbXNfZGVtbyAlPiUgc2VsZWN0KHBhdF9pZCwgZGVyX3NleCwgcGF0X3JlZ2lvbiwgcGF0X3N0YXRlLCB5b2JfZ3JvdXAsIHppcDNfZ3JvdXApCgoKdW5pcXVlX2RhdGEgPC0gc2VsZWN0ZWRfZGF0YSAlPiUgZGlzdGluY3QocGF0X2lkLCAua2VlcF9hbGwgPSBUUlVFKQoKdW5pcXVlX2RhdGEkeW9iX2dyb3VwW2lzLm5hKHVuaXF1ZV9kYXRhJHlvYl9ncm91cCldIDwtICJOQSIKdW5pcXVlX2RhdGEkemlwM19ncm91cFtpcy5uYSh1bmlxdWVfZGF0YSR6aXAzX2dyb3VwKV0gPC0gIk5BIgp1bmlxdWVfZGF0YSRwYXRfcmVnaW9uW3VuaXF1ZV9kYXRhJHBhdF9yZWdpb24gPT0gIiJdIDwtIE5BCnVuaXF1ZV9kYXRhJHBhdF9zdGF0ZVt1bmlxdWVfZGF0YSRwYXRfc3RhdGUgPT0gIiJdIDwtIE5BCgpkZXJfc2V4X3N1bW1hcnkgPC0gc3VtbWFyeSh1bmlxdWVfZGF0YSRkZXJfc2V4KQpwYXRfcmVnaW9uX3N1bW1hcnkgPC0gc3VtbWFyeSh1bmlxdWVfZGF0YSRwYXRfcmVnaW9uKQpwYXRfc3RhdGVfc3VtbWFyeSA8LSBzdW1tYXJ5KHVuaXF1ZV9kYXRhJHBhdF9zdGF0ZSkKeW9iX2dyb3VwX3N1bW1hcnkgPC0gc3VtbWFyeSh1bmlxdWVfZGF0YSR5b2JfZ3JvdXApCnppcDNfZ3JvdXBfc3VtbWFyeSA8LSBzdW1tYXJ5KHVuaXF1ZV9kYXRhJHppcDNfZ3JvdXApCgpwcmludCgiRGVyIFNleCBTdW1tYXJ5IFN0YXRpc3RpY3M6IikKcHJpbnQoZGVyX3NleF9zdW1tYXJ5KQpwcmludCgiUGF0aWVudCBSZWdpb24gU3VtbWFyeSBTdGF0aXN0aWNzOiIpCnByaW50KHBhdF9yZWdpb25fc3VtbWFyeSkKcHJpbnQoIlBhdGllbnQgU3RhdGUgU3VtbWFyeSBTdGF0aXN0aWNzOiIpCnByaW50KHBhdF9zdGF0ZV9zdW1tYXJ5KQpwcmludCgiWWVhciBvZiBCaXJ0aCBHcm91cCBTdW1tYXJ5IFN0YXRpc3RpY3M6IikKcHJpbnQoeW9iX2dyb3VwX3N1bW1hcnkpCnByaW50KCJaSVAzIEdyb3VwIFN1bW1hcnkgU3RhdGlzdGljczoiKQpwcmludCh6aXAzX2dyb3VwX3N1bW1hcnkpCgpkZXJfc2V4X3Bsb3QgPC0gZ2dwbG90KHVuaXF1ZV9kYXRhLCBhZXMoeCA9IGZhY3RvcihkZXJfc2V4KSkpICsKICBnZW9tX2JhcihmaWxsID0gJ3NreWJsdWUnLCBjb2xvciA9ICdibGFjaycpICsKICBsYWJzKHRpdGxlID0gJ0Rpc3RyaWJ1dGlvbiBvZiBTZXgnLCB4ID0gJ1NleCcsIHkgPSAnRnJlcXVlbmN5JykgKwogIHRoZW1lX21pbmltYWwoKQoKCnBhdF9yZWdpb25fcGxvdCA8LSBnZ3Bsb3QodW5pcXVlX2RhdGEsIGFlcyh4ID0gZmFjdG9yKHBhdF9yZWdpb24pKSkgKwogIGdlb21fYmFyKGZpbGwgPSAnc2FsbW9uJywgY29sb3IgPSAnYmxhY2snKSArCiAgbGFicyh0aXRsZSA9ICdEaXN0cmlidXRpb24gb2YgUGF0aWVudCBSZWdpb24nLCB4ID0gJ1JlZ2lvbicsIHkgPSAnRnJlcXVlbmN5JykgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKCnBhdF9zdGF0ZV9wbG90IDwtIGdncGxvdCh1bmlxdWVfZGF0YSwgYWVzKHggPSBmYWN0b3IocGF0X3N0YXRlKSkpICsKICBnZW9tX2JhcihmaWxsID0gJ2xpZ2h0Z3JlZW4nLCBjb2xvciA9ICdibGFjaycpICsKICBsYWJzKHRpdGxlID0gJ0Rpc3RyaWJ1dGlvbiBvZiBQYXRpZW50IFN0YXRlJywgeCA9ICdTdGF0ZScsIHkgPSAnRnJlcXVlbmN5JykgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKCnlvYl9ncm91cF9wbG90IDwtIGdncGxvdCh1bmlxdWVfZGF0YSwgYWVzKHggPSBmYWN0b3IoeW9iX2dyb3VwKSkpICsKICBnZW9tX2JhcihmaWxsID0gJ2xpZ2h0Ymx1ZScsIGNvbG9yID0gJ2JsYWNrJykgKwogIGxhYnModGl0bGUgPSAnRGlzdHJpYnV0aW9uIG9mIFllYXIgb2YgQmlydGggR3JvdXAnLCB4ID0gJ1llYXIgb2YgQmlydGggR3JvdXAnLCB5ID0gJ0ZyZXF1ZW5jeScpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCgp6aXAzX2dyb3VwX3Bsb3QgPC0gZ2dwbG90KHVuaXF1ZV9kYXRhLCBhZXMoeCA9IGZhY3Rvcih6aXAzX2dyb3VwKSkpICsKICBnZW9tX2JhcihmaWxsID0gJ29yYW5nZScsIGNvbG9yID0gJ2JsYWNrJykgKwogIGxhYnModGl0bGUgPSAnRGlzdHJpYnV0aW9uIG9mIFpJUDMgR3JvdXAnLCB4ID0gJ1pJUDMgR3JvdXAnLCB5ID0gJ0ZyZXF1ZW5jeScpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCgpkZXJfc2V4X3Bsb3QgCnBhdF9yZWdpb25fcGxvdCAKcGF0X3N0YXRlX3Bsb3QgCnlvYl9ncm91cF9wbG90IAp6aXAzX2dyb3VwX3Bsb3QgCmBgYAoKCgo=